Java JavaScript Python C# C C++ Go Kotlin PHP Swift R Ruby TypeScript Scala SQL Perl rust VisualBasic Matlab Julia

Generics → Wildcards in Generics

Generics

Wildcards in Generics

Java generics allow you to write type-safe code that can work with various types without knowing the specific type at compile time. Wildcards enhance this capability by providing flexibility when you don't need to know the *exact* type, only that it's related to a certain type or a subtype. Let's break down the different wildcard types:

1. Unbounded Wildcard (`<?>`)

This wildcard represents any type. It's useful when you don't care about the specific type parameter at all. You only need to know that it's some type.
Basic syntax public static void printList(List<?> list) { for (Object obj : list) { System.out.println(obj); } }
In this example, `printList` can accept a `List<String>`, `List<Integer>`, `List<Dog>`, or any other type of list. However, because we're using an unbounded wildcard, we can only treat the elements as `Object` within the method. We can't call type-specific methods on them. Trying `obj.toLowerCase()` would cause a compile-time error if the list contains non-String objects.

2. Upper-Bounded Wildcard (`<? extends T>`)

This wildcard specifies that the type parameter can be `T` or any subtype of `T`. `T` is the upper bound. This is very useful when you need to read from a collection but don't need to add elements.
Upper-Bounded Wildcard public static double sumList(List<? extends Number> list) { double sum = 0; for (Number num : list) { sum += num.doubleValue(); } return sum; }
Here, `sumList` can accept lists of `Integer`, `Double`, `Float`, etc., because these are all subtypes of `Number`. Within the method, we can safely call `doubleValue()` because all `Number` types have this method. Importantly, we *cannot* add elements to this list; `list.add(new Integer(5));` would be a compile-time error.

3. Lower-Bounded Wildcard (`<? super T>`)

This wildcard specifies that the type parameter can be `T` or any supertype of `T`. `T` is the lower bound. This is useful when you need to add elements to a collection, but you don't need to be precise about the type of those elements, as long as they are assignable to `T`.
Lower-Bounded Wildcard public static void addToList(List<? super Integer> list) { list.add(1); list.add(new Integer(2)); //list.add("hello"); //this would still cause an error, because String is not a supertype of Integer }
Here, `addToList` can accept lists of `Number`, `Object`, etc., because `Integer` is a subtype of these types. We can add `Integer` objects (and any subtype of `Integer`, which is none in this case) but not other types that aren't assignable to `Integer`.
Important Considerations ⯄ PECS (Producer Extends, Consumer Super) This mnemonic is a helpful way to remember when to use which wildcard. If your method produces elements from a collection (reads them), use `<? extends T>`. If your method consumes elements (adds them), use `<? super T>`. ⯄ Capture Wildcard The compiler sometimes introduces a capture wildcard (e.g., `List<? extends T>`) to resolve type inference issues, but it does not change the underlying behavior. ⯄ Wildcard limitations Wildcards can restrict what you can do with the generic type. The less you specify about your wildcard the less you can do with it inside your method. Unbounded wildcards are the most restrictive; you can only treat elements as Objects. By understanding and effectively utilizing these wildcard types, you can write more flexible and reusable generic code in Java, handling collections of different but related types in a type-safe way. Remember to choose the appropriate wildcard based on whether your method is primarily producing or consuming elements.

Tutorials